﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shell;
using System.Xml.Linq;

namespace Combination.UI
{
    #region CornerRadius 圆角
    public class CornerRadiusProperty : BaseAttachedProperty<CornerRadiusProperty, CornerRadius> { }
    #endregion

    #region Effect 阴影
    public class EffectProperty : BaseAttachedProperty<EffectProperty, Effect> { }
    #endregion

    #region Icon 图标
    /// <summary>
    /// 默认图标
    /// </summary>
    public class DataIconProperty : BaseAttachedProperty<DataIconProperty, object> { }
    public class CheckedIconProperty : BaseAttachedProperty<CheckedIconProperty, object> { }
    public class UncheckedIconProperty : BaseAttachedProperty<UncheckedIconProperty, object> { }
    public class ShowIconProperty : BaseAttachedProperty<ShowIconProperty, bool> { }
    #endregion

    #region PrefixContent 前缀内容
    public class PrefixContentProperty : BaseAttachedProperty<PrefixContentProperty, object> { }
    #endregion

    #region SuffixContent 后缀内容
    public class SuffixContentProperty : BaseAttachedProperty<SuffixContentProperty, object> { }
    #endregion

    #region WaterMark 水印
    public class WaterMarkProperty : BaseAttachedProperty<WaterMarkProperty, object> { }
    #endregion

    #region WaterMarkBrush 水印前景颜色
    public class WaterMarkBrushProperty : BaseAttachedProperty<WaterMarkBrushProperty, Brush> { }
    #endregion

    #region Window CaptionHeight
    public class CaptionHeightProperty : BaseAttachedProperty<CaptionHeightProperty, double> { }
    #endregion

    #region 标题响应Click事件
    public class IsHitTestVisibleInCaptionProperty : BaseAttachedProperty<IsHitTestVisibleInCaptionProperty, bool>
    {
        public override void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is not Control control)
                return;
            control.SetValue(WindowChrome.IsHitTestVisibleInChromeProperty, e.NewValue);
        }
    }
    #endregion

    #region Pages页面
    public class PagesProperty : BaseAttachedProperty<PagesProperty, Page> { }
    #endregion

    #region 消息按钮
    public class MessageButtonsProperty : BaseAttachedProperty<MessageButtonsProperty, MessageButtons> { }
    #endregion

    #region 显示最大化，最小化，关闭图标
    public class ShowCloseButtonProperty : BaseAttachedProperty<ShowCloseButtonProperty, bool> { }
    public class ShowMinButtonProperty : BaseAttachedProperty<ShowMinButtonProperty, bool> { }
    public class ShowMaxButtonProperty : BaseAttachedProperty<ShowMaxButtonProperty, bool> { }

    #endregion

    #region 密码输入框
    public class MonitorPasswordProperty : BaseAttachedProperty<MonitorPasswordProperty, bool>
    {
        public override void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is not PasswordBox passwordBox) return;

            passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;

            if ((bool)e.NewValue)
            {
                HasTextProperty.SetValue(passwordBox);
                passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
            }
        }

        private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
        {
            HasTextProperty.SetValue((PasswordBox)sender);
        }
    }

    public class HasTextProperty : BaseAttachedProperty<HasTextProperty, bool>
    {
        public static void SetValue(DependencyObject sender)
        {
            SetValue(sender, ((PasswordBox)sender).SecurePassword.Length > 0);
        }
    }
    #endregion

    #region 内容输入框

    public class InputModeProperty : BaseAttachedProperty<InputModeProperty, TextBoxInputMode> 
    {
        public override void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is not TextBox textbox) return;
            WindowChrome.SetIsHitTestVisibleInChrome(textbox, true);
            DataObject.AddPastingHandler(textbox, OnPaste);
            var type = (TextBoxInputMode)e.NewValue;
            if (type == TextBoxInputMode.Int || type == TextBoxInputMode.Number)
            {
                InputMethod.SetIsInputMethodEnabled(textbox, false);//数字输入和键盘禁止输入法
                textbox.PreviewTextInput -= Textbox_PreviewTextInput;
                textbox.PreviewTextInput += Textbox_PreviewTextInput;
                textbox.PreviewKeyDown -= Textbox_PreviewKeyDown;
                textbox.PreviewKeyDown += Textbox_PreviewKeyDown;
                textbox.LostFocus -= Textbox_LostFocus;
                textbox.LostFocus += Textbox_LostFocus;
            }
        }

        private void Textbox_LostFocus(object sender, RoutedEventArgs e)
        {
            var textbox = (TextBox)sender;
            CorrectInputRange(textbox, textbox.Text);
        }

        private void Textbox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            var textbox = (TextBox)sender;
            var InputMode = NUI.GetAttachedValue<InputModeProperty, TextBoxInputMode>(textbox);
            if (InputMode == TextBoxInputMode.Int || InputMode == TextBoxInputMode.Number)
            {
                if (e.Key == Key.Space || e.Key == Key.Enter)
                {
                    e.Handled = true;
                }
            }
        }

        private void Textbox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var textbox = (TextBox)sender;
            e.Handled = PreviewInputHandled(textbox, e.Text);
        }

        /// <summary>
        /// 粘贴事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
            if (!isText) return;

            var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
            var textbox = (TextBox)sender;
            if (PreviewInputHandled(textbox, text))
                e.CancelCommand();
        }

        /// <summary>
        /// 输入预处理
        /// </summary>
        /// <param name="inputText"></param>
        /// <returns>true表示已经处理</returns>
        private bool PreviewInputHandled(TextBox textbox, string inputText)
        {
            if (string.IsNullOrEmpty(inputText))
                return true;
            var InputMode = NUI.GetAttachedValue<InputModeProperty, TextBoxInputMode>(textbox);
            var val = textbox.Text.Remove(textbox.SelectionStart, textbox.SelectionLength).Insert(textbox.SelectionStart, inputText);
            if (InputMode == TextBoxInputMode.Int)
            {
                var MinInt = NUI.GetAttachedValue<MinIntProperty, long>(textbox);
                var MaxInt = NUI.GetAttachedValue<MaxIntProperty, long>(textbox);
                var ret = NUI.IsInt(val, MinInt, MaxInt);
                return !ret;
            }
            if (InputMode == TextBoxInputMode.Number)
            {
                var NumberDecimals = NUI.GetAttachedValue<NumberDecimalsProperty, int>(textbox);
                var MinNumber = NUI.GetAttachedValue<MinNumberProperty, double>(textbox);
                var MaxNumber = NUI.GetAttachedValue<MaxNumberProperty, double>(textbox);
                var ret = NUI.IsNumber(val, NumberDecimals, MinNumber, MaxNumber);
                return !ret;
            }
            var InputRegex = NUI.GetAttachedValue<InputRegexProperty, string>(textbox);
            if (!string.IsNullOrWhiteSpace(InputRegex))
            {
                try
                {
                    return !NUI.IsMatch(val, InputRegex);
                }
                catch
                {
                    return false;
                }
            }
            return false;
        }

        /// <summary>
        /// 输入范围修正
        /// </summary>
        /// <param name="val"></param>
        private void CorrectInputRange(TextBox textbox, string val)
        {
            var InputMode = NUI.GetAttachedValue<InputModeProperty, TextBoxInputMode>(textbox);
            if (InputMode == TextBoxInputMode.Int)
            {
                if (long.TryParse(val, out long lVal))
                {
                    var MinInt = NUI.GetAttachedValue<MinIntProperty, long>(textbox);
                    var MaxInt = NUI.GetAttachedValue<MaxIntProperty, long>(textbox);
                    if (lVal < MinInt)
                    {
                        textbox.Text = MinInt.ToString();
                    }
                    else if (lVal > MaxInt)
                    {
                        textbox.Text = MaxInt.ToString();
                    }
                }
            }
            else if (InputMode == TextBoxInputMode.Number)
            {
                if (double.TryParse(val, out double dVal))
                {
                    var MinNumber = NUI.GetAttachedValue<MinNumberProperty, double>(textbox);
                    var MaxNumber = NUI.GetAttachedValue<MaxNumberProperty, double>(textbox);
                    if (dVal < MinNumber)
                    {
                        textbox.Text = MinNumber.ToString();
                    }
                    else if (dVal > MaxNumber)
                    {
                        textbox.Text = MaxNumber.ToString();
                    }
                }
            }
        }
    }

    /// <summary>
    /// 输入正则表达式
    /// </summary>
    public class InputRegexProperty : BaseAttachedProperty<InputRegexProperty, string> { }
    /// <summary>
    /// 最大数字
    /// </summary>
    public class MaxNumberProperty : BaseAttachedProperty<MaxNumberProperty, double> { }
    /// <summary>
    /// 最小数字
    /// </summary>
    public class MinNumberProperty : BaseAttachedProperty<MinNumberProperty, double> { }
    /// <summary>
    /// 数字小数位
    /// </summary>
    public class NumberDecimalsProperty : BaseAttachedProperty<NumberDecimalsProperty, int> { }
    /// <summary>
    /// 最小整数
    /// </summary>
    public class MinIntProperty : BaseAttachedProperty<MinIntProperty, long> { }
    /// <summary>
    /// 最大整数
    /// </summary>
    public class MaxIntProperty : BaseAttachedProperty<MaxIntProperty, long> { }

    public class BackgroundProperty : BaseAttachedProperty<BackgroundProperty, object> { }
    #endregion

    /// <summary>
    /// TextBox输入模式
    /// </summary>
    public enum TextBoxInputMode
    {
        /// <summary>
        /// 正常输入框
        /// </summary>
        Normal = 0,

        /// <summary>
        /// 整数输入框
        /// </summary>
        Int = 1,

        /// <summary>
        /// 数字输入框
        /// </summary>
        Number = 2,
    }
}
